#include "Buffer.h"
#include <cstring>
#include <cjson/cJSON.h>

using std::cout;

int sqite3Callback(void* para, int argc, char** argv, char** columName)
{
	if (1 == argc)
	{
		if (para)
			*(int*)para = atoi(*argv);
	}
	return 0;
}


Buffer::Buffer(int deviceID,std::string dbName, std::string configTBName, std::string dataTbName)
	: deviceID(deviceID),dbName(dbName), configTableName(configTBName), dataTableName(dataTbName)
{
	int rc = sqlite3_open(dbName.c_str(), &this->db);
	if (rc != SQLITE_OK)
		std::cout << "Cant Open " << dbName << " : " << sqlite3_errmsg(this->db);

}

Buffer::~Buffer()
{
	if (db) sqlite3_free(db);
}

Buffer::Buffer(std::string dbName)
{
	int rc = sqlite3_open(dbName.c_str(), &this->db);
	if (rc != SQLITE_OK)
		std::cout << "Cant Open " << dbName << " : " << sqlite3_errmsg(this->db);
}


int Buffer::open(std::string dbName)
{
	if (db != nullptr)
		sqlite3_free(db);
	this->dbName = dbName;
	int rc = sqlite3_open(dbName.c_str(), &this->db);
	if (rc != SQLITE_OK)
		std::cout << "Cant Open " << dbName << " : " << sqlite3_errmsg(this->db);
	return rc;
}

bool Buffer::isTableExist(const std::string& tableName)const
{
	char* sql = sqlite3_mprintf("select count(*) from sqlite_master where type='table' and name = '%s';",
		tableName.c_str());
	//std::cout << sql << std::endl;
	
	int isExist;
	char* errMsg;
	int rc = sqlite3_exec(db, sql, sqite3Callback, &isExist, &errMsg);

	if (SQLITE_OK != rc)
	{
		std::cout << "isTableExist: sql error: " << errMsg;
		sqlite3_free(errMsg);
		sqlite3_free(sql);
		return false;
	}
	sqlite3_free(sql);
	return isExist;
}

bool Buffer::isTableEmpty(const std::string& tableName) const
{
	if (isTableExist(tableName))
	{
		char* sql = sqlite3_mprintf("SELECT * FROM %s;", tableName.c_str());
		char** result;
		int nRow, nCol;
		char* errMsg;
		int rc = sqlite3_get_table(db, sql, &result, &nRow, &nCol, &errMsg);
		if (SQLITE_OK != rc)
		{
			std::cerr << "sql error: " << errMsg << std::endl << sql;
			sqlite3_free(sql);
			return false;
		}
		sqlite3_free(sql);
		return !nRow;
	}
	//
	
	return false;
}

bool Buffer::isConfigExist()const
{
	if (!isTableExist(configTableName))
		return false;
	char* sql = sqlite3_mprintf("SELECT * FROM %s WHERE Device_ID=%d;", configTableName.c_str(), deviceID);

	char** result;
	int nRow, nCol;
	char* errMsg;
	int rc = sqlite3_get_table(db, sql, &result, &nRow, &nCol, &errMsg);
	if (SQLITE_OK != rc)
	{
		std::cerr << "sql error: " << errMsg << std::endl << sql;
		sqlite3_free(sql);
		return false;
	}
	sqlite3_free(sql);
	return nRow;
}

void Buffer::createConfigTable()const
{
	char* sql = sqlite3_mprintf("CREATE TABLE %s("
		"id INTEGER PRIMARY KEY AUTOINCREMENT,"
		"Device_ID INT NOT NULL,"
		"Data VARCHAR(1024));", configTableName.c_str());

	char* errMsg;
	int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
	if (SQLITE_OK != rc)
	{
		std::cout << "createConfigTbale: sql error: " << errMsg << std::endl;
		sqlite3_free(errMsg);
		sqlite3_free(sql);
		return;
	}
	sqlite3_free(sql);
}

void Buffer::createConfigTable(const char* tableName) const
{
	char* sql = sqlite3_mprintf("CREATE TABLE %s("
		"id INTEGER PRIMARY KEY AUTOINCREMENT,"
		"Device_ID INT NOT NULL,"
		"Data VARCHAR(1024));", tableName);

	char* errMsg;
	int rc = sqlite3_exec(db, sql, nullptr, nullptr, &errMsg);
	if (SQLITE_OK != rc)
	{
		std::cout << "createConfigTbale: sql error: " << errMsg << std::endl;
		sqlite3_free(errMsg);
		sqlite3_free(sql);
		return;
	}
	sqlite3_free(sql);
}
int Buffer::createDataTable() const
{
	char* sql = sqlite3_mprintf("CREATE TABLE %s("
		"id INTEGER PRIMARY KEY AUTOINCREMENT,"
		"Device_ID INTEGER NOT NULL,"
		"Data VARCHAR(1024),"
		"Data_Status INTEGER,"
		"Date VARCHAR(128));",
		dataTableName.c_str());

	char* errMsg;
	int rc = sqlite3_exec(db, sql, NULL, 0, &errMsg);
	if (rc != SQLITE_OK)
	{
		std::cerr << "无法创建数据表: " << errMsg << std::endl;
		cout << sql << std::endl;
		sqlite3_free(sql);
		return 1;
	}
	sqlite3_free(sql);
	return 0;
}

int Buffer::createDataTable(const char* tableName) const
{
	char* sql = sqlite3_mprintf("CREATE TABLE %s("
		"id INTEGER PRIMARY KEY AUTOINCREMENT,"
		"Device_ID INTEGER NOT NULL,"
		"Data VARCHAR(1024),"
		"Data_Status INTEGER,"
		"Date VARCHAR(128));",
		tableName);
	//cout << tableName << std::endl;
	char* errMsg;
	int rc = sqlite3_exec(db, sql, NULL, 0, &errMsg);
	if (rc != SQLITE_OK)
	{
		std::cerr << "无法创建数据表: " << errMsg << std::endl;
		cout << sql << std::endl;
		sqlite3_free(sql);
		return 1;
	}
	sqlite3_free(sql);
	return 0;
}

int Buffer::createOperaionTable(const char * tableName) const
{
	char* sql = sqlite3_mprintf("CREATE TABLE %s("
		"id INTEGER PRIMARY KEY AUTOINCREMENT,"
		"Device_ID INTEGER NOT NULL,"
		"Data VARCHAR(1024),"
		"Data_Status INTEGER,"
		"Date VARCHAR(128));",
		tableName);

	char* errMsg;
	int rc = sqlite3_exec(db, sql, NULL, 0, &errMsg);
	if (rc != SQLITE_OK)
	{
		std::cerr << "无法创建操作表: " << errMsg << std::endl;
		cout << sql << std::endl;
		sqlite3_free(sql);
		return 1;
	}
	sqlite3_free(sql);
	return 0;
}

int Buffer::getOperation(const std::string& tableName, std::string& operation)
{

	if (isTableExist(tableName))
	{
		if (!isTableEmpty(tableName))
		{
			char* sql = sqlite3_mprintf("select * from %s where Device_Id=%d and Data_Status=0 order by id desc;", tableName.c_str(), deviceID);
			char** result;
			char* errorMsg;
			int nRow, nCol;
			int rc = sqlite3_get_table(db, sql, &result, &nRow, &nCol, &errorMsg);
			if (rc != SQLITE_OK)
			{
				std::cerr << "读取" << tableName << "失败\n";
				sqlite3_free(sql);
				return -1;
			}
			if (nRow > 0)
			{
				operation.append(result[nCol + 2]);
				char* sqlUpdate = sqlite3_mprintf("UPDATE %s set Data_Status=1 WHERE id=%d", tableName.c_str(),atoi(result[nCol]));
				int rc = sqlite3_exec(db, sqlUpdate, NULL, NULL, &errorMsg);

				if (SQLITE_OK != rc)
				{
					std::cerr << "写入配置错误: " << configTableName << errorMsg << std::endl;
					sqlite3_free(sqlUpdate);
					return -1;
				}
				sqlite3_free(sqlUpdate);
				return nRow;

			}
			
		}
		else
		{
			return -1;
		}
	}
	else
	{
		return -1;
	}

	//
	return 0;
}


int Buffer::readConfigJsonFromBuffer(std::string& config)
{

	if (isTableExist(configTableName))
	{
		if (isConfigExist())
		{
			char* sql = sqlite3_mprintf("select * from %s where Device_Id=%d;", configTableName.c_str(), deviceID);
			char** result;
			char* errorMsg;
			int nRow, nCol;
			int rc = sqlite3_get_table(db, sql, &result, &nRow, &nCol, &errorMsg);
			if (rc != SQLITE_OK)
			{
				std::cerr << "读取" << configTableName << "失败\n";
				sqlite3_free(sql);
				return 1;
			}
			if (nRow > 1)
			{
				printf("humiture_sensor 配置大于1个选取第一个....");
			}
			if (MAX_CONFIG_LENTH > strlen(result[nCol + 1]))
			{
				config.append(result[nCol + 2]);
				sqlite3_free(sql);
				return 0;
			}
			else
			{
				std::cerr << "configuration is not valid\n";
				sqlite3_free(sql);
				return 1;
			}
		}
		else
		{
			//配置不存在
			return 1;
		}
	}
	else
	{
		//配置表不存在
		return 1;
	}
	return 1;
}

void Buffer::writeConfigJsonToBuffer(const std::string& config)const
{
	if (isTableExist(configTableName))
	{
		char* errMsg;

		if (isConfigExist())
		{
			std::cout << "写入配置中...\n";
			char* sql = sqlite3_mprintf("UPDATE %s SET Data='%s' WHERE Device_ID=%d;",
				configTableName.c_str(), config.c_str(), deviceID);
			
			int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
			if (SQLITE_OK != rc)
			{
				std::cerr << "写入配置错误: " << configTableName << errMsg << std::endl;
				sqlite3_free(sql);
			}
		}

		else
		{
			char* sql = sqlite3_mprintf("INSERT INTO %s(Device_ID, Data)"
				"VALUES(%d, '%s');",
				configTableName.c_str(), deviceID, config.c_str());
			//printf(sql);
			int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
			if (SQLITE_OK != rc)
			{
				std::cerr << "创建配置错误: " << configTableName << errMsg << std::endl;
				sqlite3_free(sql);
			}
			sqlite3_free(sql);
		}
		
	}
	else
	{
		std::cout << configTableName << " 不存在\n";
		std::cout << "创建 " << configTableName << "...\n";
		createConfigTable();
		writeConfigJsonToBuffer(config.c_str());
	}
}

int Buffer::writeDataJsonToBuffer(const std::string& data) const
{
	if (isTableExist(dataTableName))
	{
		char* sql = sqlite3_mprintf("INSERT INTO %s(Device_ID, Data, Data_Status, Date)"
			"VALUES(%d, '%s', 0, '%s');",
			dataTableName.c_str(), deviceID, data.c_str(), getCurrentTime().c_str());
		char* errMsg;
		int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
		if (SQLITE_OK != rc)
		{
			fprintf(stderr, "Record %s data error: %s", dataTableName, errMsg);
			sqlite3_free(sql);
			sqlite3_free(errMsg);
			return 1;
		}
		sqlite3_free(sql);
		return 0;
	}
	else
	{
		std::cerr << dataTableName << "数据表不存在" << " 创建数据表中...\n";
		createDataTable();
		writeDataJsonToBuffer(data);
	}
	return 0;
}

int Buffer::writeDataJsonToTable(const std::string& tbName, const std::string& data)
{
	if (isTableExist(tbName))
	{
		char* sql = sqlite3_mprintf("INSERT INTO %s(Device_ID, Data, Data_Status, Date)"
			"VALUES(%d, '%s', 0, '%s');",
			tbName.c_str(), deviceID, data.c_str(), getCurrentTime().c_str());
		char* errMsg;
		int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
		if (SQLITE_OK != rc)
		{
			fprintf(stderr, "Record %s data error: %s", tbName, errMsg);
			sqlite3_free(sql);
			sqlite3_free(errMsg);
			return 1;
		}
		sqlite3_free(sql);
		return 0;
	}
	else
	{
		std::cerr << tbName << "数据表不存在" << " 创建数据表中...\n";
		createDataTable();
		writeDataJsonToBuffer(data);
	}
	return 0;
}

std::string Buffer::getCurrentTime()const
{
	time_t timep;
	struct tm* p;
	time(&timep);
	p = gmtime(&timep);
	std::string currentTime;
	currentTime.append(std::to_string(1900 + p->tm_year));
	currentTime.append("/");
	currentTime.append(std::to_string(1 + p->tm_mon));
	currentTime.append("/");
	currentTime.append(std::to_string(p->tm_mday));
	currentTime.append(" ");
	currentTime.append(std::to_string(8 + p->tm_hour));
	currentTime.append(":");
	currentTime.append(std::to_string(p->tm_min));
	currentTime.append(":");
	currentTime.append(std::to_string(p->tm_sec));

	return currentTime;
}

//void Buffer::recordCPUSerial(std::string serial)
//{
//	if (!isTableExist("cpu_serial"))
//	{
//		const char* sql = "CREATE TABLE cpu_serial(data VARCHAR(16));";
//		char* errMsg;
//		int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
//		if (SQLITE_OK != rc)
//		{
//			std::cerr << __func__ << " : " << errMsg;
//			sqlite3_free(errMsg);
//			return;
//		}
//
//		char* sql1 = sqlite3_mprintf("INSERT INTO cpu_serial(data) VALUES (%s);", serial.c_str());
//
//		 rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
//		if (SQLITE_OK != rc)
//		{
//			std::cerr << __func__ << " : " << errMsg;
//			sqlite3_free(sql1);
//			sqlite3_free(errMsg);
//		}
//	}
//	else
//	{
//		if (isTableEmpty("cpu_serial"))
//		{
//			char* sql = sqlite3_mprintf("INSERT INTO cpu_serial(data) VALUES ('%s');", serial.c_str());
//			char* errMsg;
//			int rc = sqlite3_exec(db, sql, NULL, NULL, &errMsg);
//			if (SQLITE_OK != rc)
//			{
//				std::cerr << __func__ << " : " << errMsg;
//				sqlite3_free(sql);
//				sqlite3_free(errMsg);
//			}
//		}
//	}
//}
//
//void Buffer::registerSensor(const  Sensor &sensor)const
//{
//	cJSON* sensorJsonObj = cJSON_CreateObject();
//	cJSON* dbPath = cJSON_CreateString(sensor.buffer.dbName.c_str());
//	cJSON* dbName = cJSON_CreateString(sensor.buffer.dbName.c_str());
//	cJSON* dataTbName = cJSON_CreateString(sensor.buffer.dataTableName.c_str());
//	cJSON* configTbName = cJSON_CreateString(sensor.buffer.configTableName.c_str());
//	cJSON* date = cJSON_CreateString(getCurrentTime().c_str());
//
//	/*cJSON_AddItemToObject(sensorJsonObj, "db_path", dbPath);
//	cJSON_AddItemToObject(sensorJsonObj, "db_name", dbName);
//		cJSON_AddItemToObject(sensorJsonObj,"data_table_name",
//			cJSON_AddItemToObject(sensorJsonObj,
//				cJSON_AddItemToObject(sensorJsonObj,
//					cJSON_AddItemToObject(sensorJsonObj,*/
//	//cout << cJSON_Print
//
//}
//	
//
